home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / jade / src / unix_server.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  7KB  |  252 lines

  1. /* unix_server.c -- client/server file handling
  2.    Copyright (C) 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4.    This file is part of Jade.
  5.  
  6.    Jade is free software; you can redistribute it and/or modify it
  7.    under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2, or (at your option)
  9.    any later version.
  10.  
  11.    Jade is distributed in the hope that it will be useful, but
  12.    WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.     See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with Jade; see the file COPYING. If not, write to
  18.    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "jade.h"
  21. #include "jade_protos.h"
  22.  
  23. #include <fcntl.h>
  24. #include <string.h>
  25. #include <unistd.h>
  26. #include <sys/types.h>
  27. #include <sys/time.h>
  28. #include <sys/socket.h>
  29. #include <sys/un.h>
  30.  
  31. _PR void server_init(void);
  32. _PR void server_kill(void);
  33.  
  34. #define JADE_SOCK_NAME "~/.Jade_rendezvous"
  35.  
  36. /* List of (FILE-NAME . SOCK-FD) */
  37. static VALUE client_list;
  38.  
  39. static VALUE sym_server_open_file;
  40.  
  41. /* fd of the socket which clients connect to, or zero. */
  42. static int socket_fd = -1;
  43.  
  44. /* pathname of the socket. */
  45. static VALUE socket_name;
  46.  
  47. static void
  48. server_accept_connection(int unused_fd)
  49. {
  50.     int confd = accept(socket_fd, NULL, NULL);
  51.     if(confd >= 0)
  52.     {
  53.     /* 1. read length field
  54.        2. read LENGTH bytes for the filename
  55.        3. read the line number
  56.        4. add (FILE . SOCK-FD) to list of client files
  57.        5. call client-open-file with FILE and LINE */
  58.     u_short filenamelen;
  59.     u_long tmp;
  60.     VALUE filename, linenum;
  61.     if(read(confd, &filenamelen, sizeof(u_short)) != sizeof(u_short))
  62.         goto readerror;
  63.     filename = make_string(filenamelen + 1);
  64.     if(read(confd, VSTR(filename), filenamelen) != filenamelen)
  65.         goto readerror;
  66.     VSTR(filename)[filenamelen] = 0;
  67.     if(read(confd, &tmp, sizeof(u_long)) != sizeof(u_long))
  68.     {
  69.     readerror:
  70.         cmd_signal(sym_error,
  71.                LIST_1(MKSTR("server_make_connection:read")));
  72.         return;
  73.     }
  74.     linenum = make_number(tmp - 1);
  75.     client_list = cmd_cons(cmd_cons(filename, make_number(confd)),
  76.                    client_list);
  77.     /* lose this on exec() */
  78.     fcntl(confd, F_SETFD, 1);
  79.     cursor(curr_vw, CURS_OFF);
  80.     call_lisp2(sym_server_open_file, filename, linenum);
  81.     cursor(curr_vw, CURS_ON);
  82.     }
  83. }
  84.  
  85. _PR VALUE cmd_server_open_p(void);
  86. DEFUN("server-open-p", cmd_server_open_p, subr_server_open_p, (void), V_Subr0, DOC_server_open_p) /*
  87. ::doc:server_open_p::
  88. server-open-p
  89.  
  90. t if the edit-server is open.
  91. ::end:: */
  92. {
  93.     if(socket_fd >= 0)
  94.     return(sym_t);
  95.     return(sym_nil);
  96. }
  97.  
  98. _PR VALUE cmd_server_open(void);
  99. DEFUN_INT("server-open", cmd_server_open, subr_server_open, (void), V_Subr0, DOC_server_open, "") /*
  100. ::doc:server_open::
  101. server-open
  102.  
  103. Creates the socket (or whatever) so that the editor's client program can
  104. send us messages.
  105. ::end:: */
  106. {
  107.     VALUE name;
  108.     if(socket_fd >= 0)
  109.     return(sym_t);
  110.     name = cmd_expand_file_name(MKSTR(JADE_SOCK_NAME), sym_nil);
  111.     if(name && STRINGP(name))
  112.     {
  113.     VALUE tmp = cmd_file_exists_p(name);
  114.     if(!tmp || !NILP(tmp))
  115.     {
  116.         message("A server is already open.");
  117.         return(sym_nil);
  118.     }
  119.     socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
  120.     if(socket_fd >= 0)
  121.     {
  122.         struct sockaddr_un addr;
  123.         addr.sun_family = AF_UNIX;
  124.         strcpy(addr.sun_path, VSTR(name));
  125.         if(bind(socket_fd, (struct sockaddr *)&addr,
  126.             sizeof(addr.sun_family) + strlen(addr.sun_path)) == 0)
  127.         {
  128.         if(listen(socket_fd, 5) == 0)
  129.         {
  130.             /* lose this on exec() */
  131.             fcntl(socket_fd, F_SETFD, 1);
  132.             fcntl(socket_fd, F_SETFL, O_NONBLOCK);
  133. #ifdef HAVE_X11
  134.             /* for the x11 eventloop  */
  135.             x11_fd_read_action[socket_fd] = server_accept_connection;
  136.             FD_SET(socket_fd, &x11_fd_read_set);
  137. #endif
  138.             socket_name = name;
  139.             return(sym_t);
  140.         }
  141.         else
  142.             signal_file_error(MKSTR("bind()"));
  143.         }
  144.         else
  145.         signal_file_error(MKSTR("listen()"));
  146.     }
  147.     else
  148.         cmd_signal(sym_error, LIST_1(MKSTR("Can't make socket name")));
  149.     close(socket_fd);
  150.     socket_fd = -1;
  151.     }
  152.     else
  153.     signal_file_error(MKSTR("socket()"));
  154.     return(NULL);
  155. }
  156.  
  157. _PR VALUE cmd_server_close(void);
  158. DEFUN_INT("server-close", cmd_server_close, subr_server_close, (void), V_Subr0, DOC_server_close, "") /*
  159. ::doc:server_close::
  160. server-close
  161.  
  162. Stops listening for client messages.
  163. ::end:: */
  164. {
  165.     if(socket_fd > 0)
  166.     {
  167. #ifdef HAVE_X11
  168.     x11_fd_read_action[socket_fd] = NULL;
  169.     FD_CLR(socket_fd, &x11_fd_read_set);
  170. #endif
  171.     close(socket_fd);
  172.     socket_fd = -1;
  173.     unlink(VSTR(socket_name));
  174.     socket_name = NULL;
  175.     }
  176.     return(sym_t);
  177. }
  178.  
  179. _PR VALUE cmd_server_reply(VALUE file, VALUE rc);
  180. DEFUN("server-reply", cmd_server_reply, subr_server_reply, (VALUE file, VALUE rc), V_Subr2, DOC_server_reply) /*
  181. ::doc:server_reply::
  182. server-reply [FILE-NAME] [RETURN-CODE]
  183.  
  184. Replies to the editor client which asked us to edit the file FILE-NAME.
  185. RETURN-CODE is the optional result for the client, by default it is zero
  186. which denotes no errors. Returns nil if the file doesn't have a client.
  187. ::end:: */
  188. {
  189.     VALUE res = sym_nil;
  190.     VALUE tmp = client_list;
  191.     if(BUFFERP(file))
  192.     file = VTX(file)->tx_FileName;
  193.     else if(!STRINGP(file))
  194.     file = curr_vw->vw_Tx->tx_FileName;
  195.     client_list = sym_nil;
  196.     while(CONSP(tmp))
  197.     {
  198.     register VALUE car = VCAR(tmp);
  199.     VALUE next = VCDR(tmp);
  200.     if(!VALUE_CMP(file, VCAR(car)))
  201.     {
  202.         /* Send the result to our client. */
  203.         int con_fd = VNUM(VCDR(car));
  204.         u_long result = NUMBERP(rc) ? VNUM(rc) : 0;
  205.         if(write(con_fd, &result, sizeof(result)) != sizeof(result))
  206.         res = signal_file_error(file);
  207.         else
  208.         res = sym_t;
  209.         close(con_fd);
  210.     }
  211.     else
  212.     {
  213.         VCDR(tmp) = client_list;
  214.         client_list = tmp;
  215.     }
  216.     tmp = next;
  217.     }
  218.     return(res);
  219. }
  220.  
  221. void
  222. server_init(void)
  223. {
  224.     client_list = sym_nil;
  225.     mark_static(&client_list);
  226.     mark_static(&socket_name);
  227.     INTERN(sym_server_open_file, "server-open-file");
  228.     ADD_SUBR(subr_server_open_p);
  229.     ADD_SUBR(subr_server_open);
  230.     ADD_SUBR(subr_server_close);
  231.     ADD_SUBR(subr_server_reply);
  232. }
  233.  
  234. void
  235. server_kill(void)
  236. {
  237.     /* clean up */
  238.     VALUE tmp = client_list;
  239.     while(CONSP(tmp))
  240.     {
  241.     /* Any client-opened files still around are replied to with
  242.        a result of 5 (fail).  */
  243.     static u_long failrc = 5;
  244.     int fd = VNUM(VCDR(VCAR(tmp)));
  245.     write(fd, &failrc, sizeof(u_long));
  246.     close(fd);
  247.     tmp = VCDR(tmp);
  248.     }
  249.     client_list = sym_nil;
  250.     cmd_server_close();
  251. }
  252.